#include <algorithm>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <vector>
#include <map>
#include <unistd.h>

using namespace std;

extern "C"
double theor_probability_equal(int l, int n1, int n2, int n12) {
    std::vector<int> numerators;
    std::vector<int> denomenators;
    int i;
    // add numerators
    for (i=n1-n12+1; i<=n1; i++){
      numerators.push_back(i);
    }
    for (i=(l-n1-n2+n12+1); i<=(l-n1); i++){
        numerators.push_back(i);
    }
    for (i=1; i<=n2; i++){
      numerators.push_back(i);
    }
    // add denomenators
    for (i=1; i<=n12; i++){
      denomenators.push_back(i);
    }
    for (i=1; i<=(n2-n12); i++){
      denomenators.push_back(i);
    }
    for (i=l-n2+1; i<=l; i++){
      denomenators.push_back(i);
    }
    std::sort(numerators.begin(), numerators.end());
    std::sort(denomenators.begin(), denomenators.end());
    
//    std::cout << "numerators" << std::endl;
//    for (i=1; i<numerators.size(); i++)
//	std::cout << numerators.at(i) << " ";
//    std::cout << std::endl;
//
//    std::cout << "denomenators" << std::endl;
//    for (i=1; i<denomenators.size(); i++)
//	std::cout << denomenators.at(i) << " ";
//    std::cout << std::endl;
    
    double result = 1.0;
    while (numerators.size() or denomenators.size()) {
	if (numerators.size()) {
	  result = result * numerators.back();
	  numerators.pop_back();
	}
	if (denomenators.size()) {
	  result = result / denomenators.back();
	  denomenators.pop_back();
	}
    }
    return result;
}

extern "C"
double theor_probability_gt(int l, int n1, int n2, int n12) {
    int max_k = std::min(n1, n2);
    double result;
    if ((n12 <= max_k/2) and (n12 < 10)) {
        result = 1.0;
        for (int i=0; i<n12; i++)
            result -= theor_probability_equal(l, n1, n2, i);
    }
    else {
        result = 0;
        for (int i=n12; i<=max_k; i++) 
            result += theor_probability_equal(l, n1, n2, i);
    }
    return result;
}

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

int str2int(std::string str) {
    return atoi(str.c_str());
}


int main( int argc, char *argv[] ) {
    // some test
    //std::cout << theor_probability_equal(1204, 214,354,106) << std::endl;
    //std::cout << theor_probability_gt(1204, 214,354,106) << std::endl;

    int opt = 0;
    int genomes_num = -1;
    static const char *optString = "g:";
    
    int n1, n2, n12;
    double probability;
    std::pair<int,int> cache_key;
    std::map< std::pair<int, int>, double> probability_cache;

    string input_line;
    vector<string> splited_str, splited_str2;

    // read options
    opt = getopt( argc, argv, optString );
    while( opt != -1 ) {
        switch( opt ) {
            case 'g':
                genomes_num = atoi(optarg);
                break;
            default:
                /* сюда на самом деле попасть невозможно. */
				break;
        }
        opt = getopt( argc, argv, optString );
    }    

    if (genomes_num <=0) {
        std::cerr << "Genomes_num is incorrect: " << genomes_num << std::endl;
	return 1;
    }
    
    while(cin) {
        getline(cin, input_line);
        if (input_line.size() == 0) {
            return 0;
        }
        splited_str = split(input_line, '\t');
        if (splited_str.size() != 3) {
            cerr << "Bad gene line!" << endl;
            return 1;
        }
        splited_str2    = split(splited_str[2], ',');
        n1              = str2int(splited_str2[0]);
        n2              = str2int(splited_str2[1]);
        n12             = str2int(splited_str2[2]);

        if (n12 > float(n1*n2)/genomes_num) { // больше среднего
            cache_key = std::make_pair(n2, n12);
            if (probability_cache.count(cache_key)>0) {
                probability = probability_cache[cache_key];
            }
            else {
                probability = theor_probability_gt(genomes_num, n1, n2, n12);
                probability_cache[cache_key] = probability;
            }
            if (probability < 0.01) {
		        std::cout   << splited_str[0] << "\t" << splited_str[1] << "\t" \
    				<< probability << "\t" \
				    << n1 << "," << n2 << "," << n12 \
				    << std::endl;
    		}
        }
    }
    return 0;

}
